import {
  useMemo,
  useRef,
  useState,
  type FC,
  type MouseEvent,
} from 'react'
import {
  useSpring,
  animated,
} from '@react-spring/web'
import { useTranslation } from 'react-i18next'
import { useUnmountedRef } from '../../hooks/use-unmounted-ref'
import { withNativeProps } from '../../utils/native-props'
import { renderToContainer } from '../../utils/render-to-container'
import { withStopPropagation } from '../../utils/with-stop-propagation'
import { ShouldRender } from '../../utils/should-render'
import { useLockScroll } from '../../hooks/use-lock-scroll'
import type { MaskProps } from './type'

const classPrefix = 'rt-mask'

const opacityRecord: Record<string, number> = {
  default: 0.55,
  thin: 0.35,
  thick: 0.75,
}

const colorRecord: Record<string, string> = {
  black: '0, 0, 0',
  white: '255, 255, 255',
}

export const Mask: FC<MaskProps> = (props) => {
  const { t: translate } = useTranslation()
  const {
    afterShow,
    afterClose,
    color = 'black',
    destroyOnClose = false,
    disableBodyScroll = true,
    forceRender = false,
    getContainer = null,
    onMaskClick,
    opacity = 'default',
    stopPropagation = ['click'],
    visible = false,
    children,
  } = props

  const ref = useRef<HTMLDivElement>(null)

  useLockScroll(ref, visible && disableBodyScroll)

  const [active, setActive] = useState(visible)

  const background = useMemo(() => {
    const innerOpacity = opacityRecord[opacity] ?? opacity
    const rgb = colorRecord[color]
    return rgb ? `rgba(${rgb}, ${innerOpacity})` : color
  }, [color, opacity])

  const unmountedRef = useUnmountedRef()

  const { opacity: animatedDivOpacity } = useSpring({
    opacity: visible ? 1 : 0,
    config: {
      precision: 0.01,
      mass: 1, // 弹簧质量：回弹惯性 影响整体速度，质量越大惯性越大. default: 1
      tension: 250, // 弹簧张力：影响整体速度，张力越紧速度越快. default: 170
      friction: 30, // 摩擦力：可以与mass、tension的效果相互抵消 default 26
      clamp: true,
    },
    // animate start
    onStart: () => {
      if (visible) {
        setActive(true)
      }
    },
    // animate end
    onRest: () => {
      if (unmountedRef.current) return
      setActive(visible)
      visible ? afterShow?.() : afterClose?.()
    },
  })

  const node = withStopPropagation(
    stopPropagation,
    withNativeProps(
      props,
      <animated.div
        aria-hidden
        className={classPrefix}
        ref={ref}
        style={{
          background,
          opacity: animatedDivOpacity,
          display: active ? undefined : 'none',
        }}
        onClick={(e: MouseEvent) => {
          if (e.target === e.currentTarget) {
            onMaskClick?.(e)
          }
        }}
      >
        {onMaskClick && (
          <div
            className={`${classPrefix}-aria-button`}
            role="button"
            tabIndex={0}
            aria-label={translate('common.gallery.Mask.name')}
            onClick={onMaskClick}
          />
        )}
        <div className={`${classPrefix}-content`}>{children}</div>
      </animated.div>,
    ),
  )

  return (
    <ShouldRender
      active={active}
      forceRender={forceRender}
      destroyOnClose={destroyOnClose}
    >
      {renderToContainer(getContainer, node)}
    </ShouldRender>
  )
}
